package com.hongsuan.pplive.mobileAPI.utils;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import com.cnjson.common.utils.DateUtils;
import com.cnjson.common.utils.IdGen;
import com.google.common.io.Files;
import com.hongsuan.pplive.mobileAPI.vo.UploadFile;
import com.hongsuan.pplive.modules.sys.utils.UserUtils;

public class UploadFileUtils {

	private static Logger logger = LoggerFactory.getLogger(UploadFileUtils.class);
	private static final String IMAGE_TYPE = "jpeg||jpg||bmp||gif||png";
	/**
	 * 10M
	 */
	public static final long maxUploadSize = 10 * 1024 * 1024;

	/**
	 * the default user folder is "userfiles"
	 */
	public static final String UPLOAD_REALPATH = "/userfiles";

	public static void initUuid(HttpServletRequest request) {
		request.setAttribute("uuid", IdGen.uuid());
	}

	public static String getUuid() {
		return (String) IdGen.uuid();
	}

	/**
	 * Format the file size byte to fit show on page.
	 * 
	 * @param b
	 *            the byte size of the file
	 * @return
	 */
	public static String formatFileSize(Long b) {
		NumberFormat nf = NumberFormat.getNumberInstance();
		nf.setMaximumFractionDigits(4);

		if (b != null) {
			if (b >= 1073741824d) {
				return nf.format((b / 1073741824d)) + " GB";
			}
			if (b >= 1048576d) {
				return nf.format((b / 1048576d)) + " MB";
			}
			return nf.format((b / 1024d)) + " KB";
		}
		return "";
	}
	
	public static boolean validateSize(MultipartFile mf) throws IOException {
		long size = mf.getSize();
		if (size > UploadFileUtils.maxUploadSize) {
			return false;
		}
		return true;
	}

	/**
	 * Check the file whether if picture or not with file extension.
	 * 
	 * @param fileName
	 *            the full name of the file.
	 * @return true if picture else false.
	 */
	public static boolean isPicture(String fileName) {
		if (StringUtils.isNotEmpty(fileName)) {
			String fType = Files.getFileExtension(fileName);
			if (UploadFileUtils.IMAGE_TYPE.contains(fType)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Check file whether if image or not by file input Stream.
	 * 
	 * @param newFile
	 *            the file is input or upload.
	 * @return true if is image else false.
	 */
	public static boolean isImage(File newFile) {
		try {
			BufferedImage bi = ImageIO.read(newFile);
			if (bi != null) {
				return true;
			}
		} catch (IOException e) {
			return false;
		}
		return false;
	}

	public static String removeImageType(String name) {
		if (StringUtils.isNotEmpty(name)) {
			return Files.getNameWithoutExtension(name);
		}
		return "";
	}

	/**
	 * 获取上传路径 {@link UPLOAD_REALPATH},fetch the "userfiles" folder real path.
	 *
	 * @return
	 */
	public static String getUploadPath() throws IOException {
		String path = Thread.currentThread().getContextClassLoader().getResource("/").getPath();
		File file = new File(path);
		if (file != null && file.getParentFile() != null) {
			File webRoot = file.getParentFile().getParentFile();
			String root = webRoot.getAbsolutePath();
			File upload = new File(root, UPLOAD_REALPATH);
			if (!upload.exists()) {
				upload.mkdirs();
			}

			// 如果目录不存在则创建目录，创建失败则抛出异常
			/*
			 * if ((!upload.isDirectory() || !upload.exists()) &&
			 * !upload.mkdirs()) { throw new IOException("创建目录失败"); }
			 */

			return upload.getAbsolutePath();
		}
		return file.getAbsolutePath();

	}

	/**
	 * Get current time format path such as yyyyMMdd
	 * 
	 * @return
	 */
	public static String getTimePath() {
		return DateUtils.formatDate(new Date(), "yyyyMMdd");
	}

	/**
	 * Format the given time as yyyyMMdd
	 * 
	 * @param date
	 *            the given date.
	 * @return file name date format.
	 */
	public static String formatTimeToPath(Date date) {
		return DateUtils.formatDate(date, "yyyyMMdd");
	}

	public static String getDomain(HttpServletRequest request) {
		String retUrl = "";
		if (request != null) {
			StringBuffer url = request.getRequestURL();
			retUrl = url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
		}
		return retUrl;
	}

	/**
	 * Init file upload path.
	 * 
	 * @param folder
	 *            the current login user id.
	 * @param suffix
	 *            file extension
	 * @return {@link UploadFile}
	 */
	private static UploadFile initFileUpload(HttpServletRequest request, String folder, String suffix)
			throws IOException {
		int random = (int) (Math.random() * 9000 + 1000);
		String randomKey = String.valueOf(random);
		Date date = new Date();
		String dateStr = new SimpleDateFormat("yyyyMMdd").format(date);
		String timeStr = new SimpleDateFormat("HHmmssSSS").format(date);
		String relativePath = StringUtils.join(UPLOAD_REALPATH, File.separator, folder, File.separator, dateStr);
		UploadFile vo = new UploadFile();
		String realPath = getRequestRealPath(request, relativePath);
		File saveFile = new File(realPath);
		saveFile.setWritable(true, false);
		if (!saveFile.exists()) {
			saveFile.mkdirs();
		}
		String fileName = StringUtils.join(timeStr, randomKey);
		if (StringUtils.isNotEmpty(suffix)) {
			fileName = StringUtils.join(fileName, ".", suffix);
		}
		// uploadFile.setFileUuId(getUuid());
		String fullPath = StringUtils.join(getDomain(request), relativePath, File.separator, fileName);
		String relate = StringUtils.join(relativePath, File.separator, fileName);
		vo.setFileName(fileName);
		vo.setRelativePath(relate);
		vo.setRealPath(fullPath);
		return vo;
	}

	/**
	 * Try to deal with the HttpServletRequest file path object.
	 * 
	 * @param request
	 *            {@link HttpServletRequest}
	 * @param userId
	 *            the target of the user id to save different folder.
	 * @param originalFilename
	 *            the original file name.
	 * @return
	 * @throws IOException
	 *             occur if exception with null user or other IO failed.
	 */
	public static UploadFile dealFilePath(HttpServletRequest request, String userId, String originalFilename)
			throws IOException {
		if (StringUtils.isEmpty(userId)) {
			userId = UserUtils.getUser().getId();
			if (StringUtils.isEmpty(userId))
				throw new IOException("The current user is null or empty!");
		}
		String originalExt = Files.getFileExtension(originalFilename);
		UploadFile uploadFile = UploadFileUtils.initFileUpload(request, userId, originalExt);
		uploadFile.setOriginalFilename(originalFilename);
		return uploadFile;
	}
 
	public static String getRequestRealPath(HttpServletRequest request, String relativePath) {
		if (request == null)
			return relativePath;

		if (StringUtils.isEmpty(relativePath))
			return request.getSession().getServletContext().getContextPath();

		return request.getSession().getServletContext().getRealPath(relativePath);
	}

	/**
	 * 上传多个文件
	 * 
	 * @param request
	 * @throws Exception
	 */
	public static void uploadMutrilFile(String userId, HttpServletRequest request) throws Exception {
		try {
			request.setCharacterEncoding("utf-8");
			// MultipartHttpServletRequest multipartRequest
			// =(MultipartHttpServletRequest) request;
			// MultipartFile mf = multipartRequest.getFile("img");
			// 获得磁盘文件条目工厂。
			DiskFileItemFactory factory = new DiskFileItemFactory();
			// 获取文件上传需要保存的路径，upload文件夹需存在。
			String path = request.getSession().getServletContext().getRealPath(UploadFileUtils.UPLOAD_REALPATH);
			// 设置暂时存放文件的存储室，这个存储室可以和最终存储文件的文件夹不同。因为当文件很大的话会占用过多内存所以设置存储室。
			factory.setRepository(new File(path));
			// 设置缓存的大小，当上传文件的容量超过缓存时，就放到暂时存储室。
			factory.setSizeThreshold(1024 * 1024);
			// 上传处理工具类（高水平API上传处理？）
			ServletFileUpload upload = new ServletFileUpload(factory);

			// 调用 parseRequest（request）方法 获得上传文件 FileItem 的集合list 可实现多文件上传。
			List<FileItem> list = (List<FileItem>) upload.parseRequest(request);
			for (FileItem item : list) {
				// 获取表单属性名字。
				String name = item.getFieldName();
				// 如果获取的表单信息是普通的文本信息。即通过页面表单形式传递来的字符串。
				if (item.isFormField()) {
					// 获取用户具体输入的字符串，
					String value = item.getString();
					request.setAttribute(name, value);
				}
				// 如果传入的是图片，音频，视频等二进制文件。
				else {
					// 获取路径名
					String value = item.getName();
					int start = value.lastIndexOf("\\");
					String filename = value.substring(start + 1);
					request.setAttribute(name, filename);
					logger.info("获取文件总量的容量:" + item.getSize());

					if (!UploadFileUtils.isPicture(filename)) {
						logger.error("It is not picture file not allow to upload!");
						continue;
					}
					if (item.getSize() > UploadFileUtils.maxUploadSize) {
						logger.error("File size exceeds the allowable range!");
						continue;
					}
					// 收到写到接收的文件中。
					String savePath = StringUtils.join(path, File.separator, userId, File.separator, "album",
							File.separator, filename);
					OutputStream out = new FileOutputStream(new File(savePath));
					InputStream in = item.getInputStream();
					int length = 0;
					byte[] buf = new byte[1024];
					while ((length = in.read(buf)) != -1) {
						out.write(buf, 0, length);
					}
					in.close();
					out.close();
				}
			}
		} catch (Exception e) {
			// logger.error(e.getMessage());
			// e.printStackTrace();
			throw e;
		}
	}
	
	
}
